﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BaseCardTypes = Wormhole.Engine.CardLibrary.BaseCardTypes;

namespace Wormhole.Engine.Player
{
	/// <author>Rodney McKay</author>
	/// <date>28 March 2008</date>
	/// <summary>
	/// This class is used to contain player information.
	/// </summary>
	public class Player
	{
		#region Constants
		/// <summary>
		/// The player's hand size.
		/// </summary>
		public const int HAND_SIZE = 8;
		#endregion

		#region Delegates
		/// <summary>
		/// The delegate for the power changed event.
		/// </summary>
		/// <param name="power">The new power value.</param>
		public delegate void PowerChangedDelegate(int power);

		/// <summary>
		/// The delegate for the event that is raised when the player chooses to keep his hand.
		/// </summary>
		public delegate void KeptHandDelegate();

		/// <summary>
		/// The delegate for the event that is raised when the player elects to take a mulligan.
		/// </summary>
		public delegate void TookMulliganDelegate();

		/// <summary>
		/// The delegate for player action events.
		/// </summary>
		/// <param name="player">The player the event is for</param>
		public delegate void PlayerActionDelegate(Player player);
		#endregion

		#region Events
		/// <summary>
		/// This event is raised when the power value changes.
		/// </summary>
		public event PowerChangedDelegate PowerChanged;

		/// <summary>
		/// This event is raised when the player keeps his hand of cards.
		/// </summary>
		public event KeptHandDelegate KeptHand;

		/// <summary>
		/// This event is raised when the player takes a mullican.
		/// </summary>
		public event TookMulliganDelegate TookMulligan;

		/// <summary>
		/// This event is fired when the player gets priority.
		/// </summary>
		public event PlayerActionDelegate GotPriority;
		#endregion

		#region Properties

		#region Game
		/// <summary>
		/// The game the player is part of.
		/// </summary>
		public Game Game { get; set; }
		#endregion

		#region Name
		/// <summary>
		/// The player name.
		/// </summary>
		public string Name { get; set; }
		#endregion

		#region Score
		/// <summary>
		/// The player score.
		/// </summary>
		public Score Score { get; set; }
		#endregion

		#region Random Seed
		/// <summary>
		/// The seed to use for randomization.
		/// </summary>
		public int RandomSeed { get; set; }
		#endregion

		#region All Cards
		/// <summary>
		/// All the card that belongs to the player.
		/// </summary>
		public Decks.Deck AllCards { get; set; }
		#endregion

		#region Deck
		/// <summary>
		/// The players complete card deck.
		/// </summary>
		public Decks.Deck Deck { get; set; }
		#endregion

		#region Graveyard
		/// <summary>
		/// The player graveyard.
		/// </summary>
		public Decks.Deck Graveyard { get; private set; }
		#endregion

		#region Cards In Hand
		/// <summary>
		/// The cards in the player's hand.
		/// </summary>
		public Decks.HandCards CardsInHand { get; set; }
		#endregion

		#region Team 
		/// <summary>
		/// The player's team cards.
		/// </summary>
		public Decks.TeamCards Team { get; set; }
		#endregion

		#region Unassigned Support
		/// <summary>
		/// The unassigned support cards.
		/// </summary>
		public Decks.SupportCards UnassignedSupport { get; set; }
		#endregion

		#region Unassigned Adversaries
		/// <summary>
		/// The unassigned adversaries.
		/// </summary>
		public Decks.AdversaryCards UnassignedAversaries { get; private set; }
		#endregion

		#region Missions
		/// <summary>
		/// The missions card pile.
		/// </summary>
		public Decks.MissionCards Missions { get; set; }
		#endregion

		#region User Input
		/// <summary>
		/// The class used to retrieve user input.
		/// </summary>
		public Input.UserInput UserInput { get; set; }
		#endregion

		#region Power
		private int _power;
		/// <summary>
		/// The power the player has available.
		/// </summary>
		public int Power
		{
			get
			{
				return this._power;
			}

			set
			{
				if (this._power != value)
				{
					this._power = value;
					this.OnPowerChanged(this._power);
				}
			}
		}
		#endregion

		#region HasPriority
		/// <summary>
		/// Does the player have priority.
		/// </summary>
		public bool HasPriority 
		{ 
			get; 
			internal set; 
		}
		#endregion

		#endregion

		#region Constructor
		///// <summary>
		///// Initialize a new default instance of the class.
		///// </summary>
		public Player(Game game)
		{
			this.Game = game;
			this.Initialize();
		}
		#endregion

		#region Initialize
		/// <summary>
		/// Initialize the class.
		/// </summary>
		protected void Initialize()
		{
			// initialize the game objects
			this.Name = "Player";
			this.Score = new Score();
			this.Deck = new Decks.Deck(this);
			this.Graveyard = new Decks.Deck(this);
			this.AllCards = new Wormhole.Engine.Decks.Deck(this);
			this.CardsInHand = new Decks.HandCards(this);
			this.Team = new Decks.TeamCards(this);
			this.UnassignedSupport = new Decks.SupportCards(this);
			this.UnassignedAversaries = new Decks.AdversaryCards(this);
			this.Missions = new Decks.MissionCards(this);
			this.UserInput = new Wormhole.Engine.Input.UserInput(this);

			// wire up the events
			this.SetEngineEvents();
		}
		#endregion

		#region Set Engine Events
		/// <summary>
		/// Wire up the engine event handlers.
		/// </summary>
		protected void SetEngineEvents()
		{
			this.CardsInHand.CardPlayed += new Wormhole.Engine.Decks.HandCards.CardPlayedDelegate(CardsInHand_CardPlayed);
			this.CardsInHand.EventPlayed += new Wormhole.Engine.Decks.HandCards.CardPlayedDelegate(CardsInHand_EventPlayed);
			this.CardsInHand.SupportPlayed += new Wormhole.Engine.Decks.HandCards.CardPlayedDelegate(CardsInHand_SupportPlayed);
			this.CardsInHand.AdversaryPlayed += new Wormhole.Engine.Decks.HandCards.CardPlayedDelegate(CardsInHand_AdversaryPlayed);
			this.Deck.MissionCardsRemoved += new Wormhole.Engine.Decks.Deck.MissionCardsRemovedDelegate(Deck_MissionCardsRemoved);
			this.Deck.TeamCardsRemoved += new Wormhole.Engine.Decks.Deck.TeamCardsRemovedDelegate(Deck_TeamCardsRemoved);
		}
		#endregion

		#region Event Handlers

		#region Card Played
		/// <summary>
		/// The event handler for when a card is played form the player's hand.
		/// </summary>
		/// <param name="card">The card that was played.</param>
		private void CardsInHand_CardPlayed(Wormhole.Engine.CardLibrary.BaseCardTypes.Card card)
		{
			this.OnCardPlayed(card);
		}
		#endregion

		#region Event Played
		/// <summary>
		/// This event handler is fired when an event card is played from the hand.
		/// </summary>
		/// <param name="card">The event card that was played.</param>
		void CardsInHand_EventPlayed(Wormhole.Engine.CardLibrary.BaseCardTypes.Card card)
		{
			this.OnEventPlayed(card);
		}
		#endregion

		#region Support Played
		/// <summary>
		/// The event handlder for when a support card is played form cards in the player's hand.
		/// </summary>
		/// <param name="card"></param>
		void CardsInHand_SupportPlayed(Wormhole.Engine.CardLibrary.BaseCardTypes.Card card)
		{
			this.OnSupportPlayed(card);
		}
		#endregion

		#region Adversary Played
		/// <summary>
		/// Handle the event that is raised when an adversary is played.
		/// </summary>
		/// <param name="card"></param>
		void CardsInHand_AdversaryPlayed(Wormhole.Engine.CardLibrary.BaseCardTypes.Card card)
		{
			this.OnAdversaryPlayed(card);
		}
		#endregion

		#region Mission Cards Removed
		/// <summary>
		/// The event handler for when mission cards is removed from the deck.
		/// </summary>
		/// <param name="missionCards">The mission cards that were removed.</param>
		private void Deck_MissionCardsRemoved(List<Wormhole.Engine.CardLibrary.BaseCardTypes.Card> missionCards)
		{
			this.AddMissionCards(missionCards);
		}
		#endregion

		#region Team Cards Removed
		/// <summary>
		/// The event handler that is invoked when the team cards are removed from the deck.
		/// </summary>
		/// <param name="teamCards">The team cards that were removed.</param>
		private void Deck_TeamCardsRemoved(List<Wormhole.Engine.CardLibrary.BaseCardTypes.Card> teamCards)
		{
			this.AddTeamCards(teamCards);
		}
		#endregion

		#endregion

		#region Add Mission Cards
		/// <summary>
		/// Add mission cards to the mission pile.
		/// </summary>
		/// <param name="missionCards">The cards that should be added.</param>
		protected void AddMissionCards(List<Wormhole.Engine.CardLibrary.BaseCardTypes.Card> missionCards)
		{
			foreach (BaseCardTypes.Card mission in missionCards)
			{
				this.Missions.Add(mission);
			}
		}
		#endregion

		#region Add Team Cards
		/// <summary>
		/// Add team cards to the team deck.
		/// </summary>
		/// <param name="teamCards">The cards that should be added.</param>
		private void AddTeamCards(List<Wormhole.Engine.CardLibrary.BaseCardTypes.Card> teamCards)
		{
			foreach (BaseCardTypes.Card team in teamCards)
			{
				this.Team.Add(team);
			}
		}
		#endregion

		#region On Card Played
		/// <summary>
		/// Handles the event when a card is played.
		/// </summary>
		/// <param name="card">The card that was played.</param>
		protected void OnCardPlayed(Wormhole.Engine.CardLibrary.BaseCardTypes.Card card)
		{
			this.CardsInHand.Remove(card);
		}
		#endregion

		#region On Event Played
		/// <summary>
		/// Handles the event when an event card is played.
		/// </summary>
		/// <param name="card">The card that was played.</param>
		protected void OnEventPlayed(Wormhole.Engine.CardLibrary.BaseCardTypes.Card card)
		{
		}
		#endregion

		#region On Support Played
		/// <summary>
		/// Handles the event when a support card is played.
		/// </summary>
		/// <param name="card">The card that was played.</param>
		protected void OnSupportPlayed(Wormhole.Engine.CardLibrary.BaseCardTypes.Card card)
		{
			this.UnassignedSupport.Add(card);
		}
		#endregion

		#region On Adversary Played
		/// <summary>
		/// Handle the event when an adversary is played.
		/// </summary>
		/// <param name="card">The adversary card which was played.</param>
		protected void OnAdversaryPlayed(CardLibrary.BaseCardTypes.Card card)
		{
			this.UnassignedAversaries.Add(card);
		}
		#endregion

		#region Fill Hand
		/// <summary>
		/// Fill the player's hand.
		/// </summary>
		public void FillHand()
		{
			for (int i = 0; i < HAND_SIZE; i++)
			{
				this.Deck.TakeCard();
			}
		}
		#endregion

		#region Remove Cards From Hand
		/// <summary>
		/// Remove all the cards from the players hand and return them to the deck.
		/// </summary>
		public void RemoveCardsFromHand()
		{
			Decks.Deck remove = new Decks.Deck();

			// add the cards to remove back to the deck
			foreach (BaseCardTypes.Card card in this.CardsInHand)
			{
				remove.Add(card);
				this.Deck.Add(card);
			}

			// remove the cards form the hand
			foreach (BaseCardTypes.Card card in remove)
			{
				this.CardsInHand.Remove(card);
			}

			// shuffle the deck
			this.Deck.Shuffle();
		}
		#endregion

		#region On Power Changed
		/// <summary>
		/// Raise the power changed event.
		/// </summary>
		/// <param name="power">The new power value.</param>
		protected void OnPowerChanged(int power)
		{
			if (this.PowerChanged != null)
				this.PowerChanged(power);
		}
		#endregion

		#region Initialize All Cards
		/// <summary>
		/// Setup the all cards collection.
		/// </summary>
		public void InitializeAllCards()
		{
			foreach (BaseCardTypes.Card card in this.Deck)
			{
				this.AllCards.Add(card);
			}
		}
		#endregion

		#region Keep Hand
		/// <summary>
		/// Keep the cards that were dealt when the game started.
		/// </summary>
		public void KeepHand()
		{
			// raise the event
			this.OnKeptHand();
		}
		#endregion

		#region Take Mulligan
		/// <summary>
		/// At the start of the game take a mulligan.
		/// </summary>
		public void TakeMulligan()
		{
			// take the mulligan
			this.RemoveCardsFromHand();
			this.FillHand();

			// raise the event
			this.OnTookMulligan();
		}
		#endregion

		#region On Kept Hand
		/// <summary>
		/// Raise the kept hand event.
		/// </summary>
		protected void OnKeptHand()
		{
			if (this.KeptHand != null)
				this.KeptHand();
		}
		#endregion

		#region On Took Mulligan
		/// <summary>
		/// Raise the took mulligan event.
		/// </summary>
		protected void OnTookMulligan()
		{
			if (this.TookMulligan != null)
				this.TookMulligan();
		}
		#endregion

		#region Give Priority
		/// <summary>
		/// Give the player priority.
		/// </summary>
		public void GivePriority()
		{
			this.HasPriority = true;
			this.OnGotPriority(this);
		}
		#endregion

		#region OnGotPriority
		/// <summary>
		/// Raise the got priority event.
		/// </summary>
		protected void OnGotPriority(Player player)
		{
			if (this.GotPriority != null)
				this.GotPriority(player);
		}
		#endregion
	}
}
